package tech.lingrui.mnpanonymousservice.service.impl;

import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import tech.lingrui.mnpanonymousservice.model.bean.GameModel;
import tech.lingrui.mnpanonymousservice.model.bean.Question;
import tech.lingrui.mnpanonymousservice.model.bean.Round;
import tech.lingrui.mnpanonymousservice.model.bean.UserModel;
import tech.lingrui.mnpanonymousservice.model.message.GameInfoMessage;
import tech.lingrui.mnpanonymousservice.model.message.ResponseMessage;
import tech.lingrui.mnpanonymousservice.service.GameService;
import tech.lingrui.mnpanonymousservice.util.ThreadPoolExecutorFactory;
import tech.lingrui.mnpanonymousservice.websocket.GameWebSocket;

import java.util.HashMap;
import java.util.Map;
import java.util.Optional;

import static tech.lingrui.mnpanonymousservice.websocket.GameWebSocket.games;

/**
 * 游戏服务接口实现类
 *
 * @author lqs2
 * @date 2018/11/25, Sun
 */
@Service
@Slf4j
public class GameServiceImpl implements GameService {




    @Override
    public GameModel createGame(UserModel model) throws Exception {
        GameModel gameModel = new GameModel();
        gameModel.setCreator(model);

        gameModel.setState(GameModel.STATE_WAITING_USER);
        games.put(gameModel.getId(), gameModel);
        ThreadPoolExecutorFactory.getThreadPoolExecutor().execute(() -> {
            try {
                Thread.sleep(1000 * 60 * 10);
                if (gameModel.getState() == GameModel.STATE_WAITING_USER) {
                    gameModel.setState(GameModel.STATE_TIME_OUT);
                }
            } catch (InterruptedException e) {
                log.error("", e);
            }
        });
        return gameModel;
    }


    @Override
    public synchronized boolean joinGame(String gameId, UserModel participate) throws Exception {
        GameModel gameModel = getGameInfo(gameId);
        if (gameModel.getState() != GameModel.STATE_TIME_OUT) {
            if (gameModel.getState() == GameModel.STATE_WAITING_USER && gameModel.getParticipant() == null) {
                gameModel.setParticipant(participate);
                gameModel.setState(GameModel.STATE_WAITING_START);
                return true;
            }
        }
        return false;
    }

    @Override
    public void startGame(String gameId) throws Exception {
        GameModel gameModel = getGameInfo(gameId);
        if (gameModel.getState() == GameModel.STATE_PROCESSING) {
            return;
        }
        gameModel.setState(GameModel.STATE_PROCESSING);
        generateQs(gameModel);
    }

    @Override
    public void randomMatch(UserModel model) throws Exception {
        Map<UserModel, GameWebSocket> clients = GameWebSocket.getClients();
        model.setState(UserModel.USER_STATE_WAITING);
        final boolean[] successFlag = {false};
        ThreadPoolExecutorFactory.getThreadPoolExecutor().execute(() -> {
            while (!successFlag[0] && (model.getState() == UserModel.USER_STATE_WAITING)) {
                Optional<UserModel> first = clients.keySet()
                        .stream()
                        .filter(u -> (u.getState() == UserModel.USER_STATE_WAITING) && !u.equals(model))
                        .findFirst();
                if (first.isPresent()) {

                    log.info("{}", model);
                    UserModel model1 = first.get();
                    log.info("{}, {}, {}", "匹配成功", model, model1);

                    model1.setState(UserModel.USER_STATE_GAME);
                    model.setState(UserModel.USER_STATE_GAME);
                    try {
                        //设置游戏参数
                        GameModel game = createGame(model1);
                        games.put(game.getId(),game);
                        game.setParticipant(model);
                        game.setWinnerIntegral(5);
                        game.setLoserIntegral(5);
                        generateQs(game);

                        //构建消息发送给指定客户端
                        GameInfoMessage message = new GameInfoMessage(game);
                        ResponseMessage responseMessage = new ResponseMessage();
                        responseMessage.setData(message);
                        responseMessage.setType(ResponseMessage.MSY_TYPE_GAME);
                        clients.get(model).sendMessageToUser(model.getName(),responseMessage);
                        clients.get(model1).sendMessageToUser(model1.getName(),responseMessage);
                        log.info("{}", game);

                        RoundServiceImpl roundService = new RoundServiceImpl(game);
                        roundService.startFirstRound();
                        game.setRoundHandler(roundService);
                        successFlag[0] = true;
                        break;
                    } catch (Exception e) {
                        log.error("", e);
                    }
                    continue;
                }
                log.info("{}", model.getName() + "正在努力寻找队友");
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    log.error("", e);
                }
            }
        });
    }

    @Override
    public void finishGame() throws Exception {

    }

    @Override
    public GameModel getGameInfo(String gameId) throws Exception {
        return games.get(gameId);
    }

    @Override
    public int getCurrGameModel(String gameId) throws Exception {
        return getGameInfo(gameId).getRoundNo();
    }

    /**
     *处理用户发来的答案
     * */
    @Override
    public void handleAnswerFromUser(String gameId, int answer) {
        GameModel gameModel = games.get(gameId);
        RoundServiceImpl roundHandler = gameModel.getRoundHandler();
        roundHandler.handleAnswer(answer);
    }

    /**
     * 为游戏随机生成问题
     *
     * @param model 游戏模型
     */
    private void generateQs(GameModel model) {
        Map<Integer, Round> rounds = new HashMap<Integer, Round>(16) {{
            for (byte i = 0; i < 10; i++) {
                Round round = new Round();
                round.setRoundNo(i+1);
                round.setQuestion(new Question(String.format("问题【%d】", i + 1), "选项A", "选项B", "选项C", "选项D", Question.NO_A));
                put(i + 1, round);
            }
        }};
        model.setRounds(rounds);
    }
}
